﻿using System;

using Microsoft.Xna.Framework;

using ZoeEngine.Framework;
using ZoeEngine.Services.Scene;
using ZoeEngine.Services.Input;
using ZoeEngine.Services.Content;
using ZoeEngine.Services.Physics;

namespace ZoeEngine
{
    public class Zoe
    {
        public static DebugMode DEBUG_MODE;

        private static Game _game = null;
        private static bool _initialized = false;

        protected static ISceneService _sceneService = null;
        protected static IContentService _contentService = null;
        protected static IInputService _inputService = null;
        protected static IPhysicsService _physicsService = null;

        /// <summary>
        /// Starts the engine. Initializes all critical game services to their default
        /// values if no alternatives have been specified by the user.
        /// </summary>
        /// <param name="game">Instance of XNA Game to run the engine for.</param>
        public static void Boot(Game game)
        {

            if (_initialized)
                throw new InvalidOperationException("Engine is already initialized.");

            if (game == null)
                throw new InvalidOperationException("Could not initialize engine for the given Xna.Framework.Game instance. Make sure the game itself has been initialized.");

            _game = game;


            if (_contentService == null)
            {
                _contentService = new ContentProvider(game);
            }
            game.Components.Add(_contentService);

            if (_sceneService == null)
            {
                _sceneService = new SceneProvider(game);
            }
            game.Components.Add(_sceneService);

            if (_inputService == null)
            {
                _inputService = new InputProvider(game);
            }
            game.Components.Add(_inputService);

            if (_physicsService == null)
            {
                _physicsService = new PhysicsProvider(game);
            }
            game.Components.Add(_physicsService);

            _initialized = true;
        }

        /// <summary>
        /// Method that allows game objects to retrieve reference to a required
        /// service without immediate access to the game object.
        /// </summary>
        /// <typeparam name="T">Type of the service to retrieve.</typeparam>
        /// <returns>Service of the specified type registered with the current game object.</returns>
        public static T GetService<T>()
        {
            if (_initialized)
                return (T)_game.Services.GetService(typeof(T));

            throw new ArgumentException("Cannot retrieve the requested service, engine has not been initialized");
        }

        /// <summary>
        /// Allocates a new entity and registers it with the 
        /// </summary>
        /// <param name="name">Optionally assign a name to the entity.</param>
        /// <returns>Reference to the newly allocated entity.</returns>
        public static Entity CreateEntity(string name = null)
        {
            Entity e = new Entity(name);
            e.Manager = _sceneService.Manager;
            _sceneService.Manager.Add(e);

            return e;
        }
    }

    [Flags]
    public enum DebugMode
    {
        NO_DEBUG = 0x0,
        PHYSICS = 0x1
    }
}
